import MathEx from '../../../Core/Math/MathEx';
import { EnumUtil } from './../../../conventions/EnumUtil';
import { JXMath } from './../../../conventions/JXCommon';
import { INVALID_VALUE } from './../../../Core/CoreDefine';
import { PART_PROPTS } from './../../Common/Define';
import { JXBattleCb } from './JXBattleCb';
import { JXBattleEvt, JXBtlArrIx, JXBtlBEM, JXBtlBEMT, JXBtlCamp, JxBtlCollisionType, JXBtlEntityType, JXBtlPs, JXBtlRT, JXBtlSSM, JXBtlST } from './JXBattleDefine';
import JXBtlMgr from './JXBattleManager';
import { JXBattleBuff, JXBattleSkill } from './JXBattleSkill';
import { JXBattleBuffTake } from './JXBattleStep';
import JXBattleTeam from './JXBattleTeam';
import { JXBattleMap, JXBattleUtility } from './JXBattleUtility';
import JXRBCmdMgr from './JXRBCmdMgr';
import { JXRBRole } from './JXRBRole';
/** 参战实体：表示所有影响战斗的对象 */
export class JXBattleEntity {

	/** 实体类型(根据作用来表示) */
	public type: JXBtlEntityType;
	/** 角色类型 */
	public roleType: JXBtlRT;
	/** 实体阵营 */
	public camp: JXBtlCamp = JXBtlCamp.NoCamp;

	/** 碰撞类型 */
	public collision: JxBtlCollisionType;
	/** id: 唯一标识 */
	public id: string;
	/** 站位，用来判断位置和排序的依据，同一种属性的站位应该完全不一致 */
	public posiiton: number;
	/**种族类型 */
	public raceType: number;
	/**当前回合的需要执行的主动技能 */
	public curInitiSkillId: number = INVALID_VALUE;
	private _cmd: JXRBCmdMgr = null;
	public get cmd() {
		return this._cmd;
	}
	public set cmd(v) {
		this._cmd = v;
	}
	/**cd時間 */
	private _cd: number = 0;
	public set cd(time: number) {
		this._cd = time
	}

	public get cd(): number {
		return this._cd;
	}

	private _curTime: number = 0;
	public get cTime() {
		return this._curTime
	}
	public set cTime(v: number) {
		this._curTime = v;
	}
	/** 当前行动次数 */
	public curRound: number = 1;


	/** 最大血量 */
	protected _maxHp: number;
	public set maxHp(val: number) {
		this.propts[JXBtlPs.R.PORPTS.MAXHP] = this._maxHp = val;
	}
	public get maxHp(): number {
		if (this.collision != JxBtlCollisionType.Normal) {
			return 0;
		}
		return this._maxHp;
	}

	/** 当前血量 */
	protected _curHp: number;
	public set curHp(val) {
		this.propts[JXBtlPs.R.PORPTS.CURHP] = this._curHp = val;
	}
	public get curHp(): number {
		if (this.collision != JxBtlCollisionType.Normal) {
			return 0;
		}
		return this._curHp;
	}


	/** 血量盾，血量的替代物 */
	protected _tempHp: number;
	public set tempHp(value) {
		this.propts[JXBtlPs.R.PORPTS.PROTECT] = this._tempHp = value;
	}
	public get tempHp() { return this._tempHp || 0; }

	/** 当前属性 */
	public propts: number[];
	/** 环境加成：属性部分 */
	public proptEnvs: number[];
	/** 属性缓存 : 各种属性计算后的缓存 */
	public proptCaches: number[];
	public heroType: number;
	// /** 角色身上的技能 */
	public skills: JXBattleSkill[];
	// /** 角色身上的BUFF */
	public buffs: JXBattleBuff[];
	// /** 以BUFF-ID为索引 */
	public buffMaps: JXBattleMap<number, JXBattleBuff[]>;
	// /** control-buffs: 由该角色控制周期的BUFF */
	public controlBuffs: JXBattleBuff[];

	/** 角色的一些标志位 */
	public flag: number = 0;
	/**攻击范围的id */
	public scopeId: number = INVALID_VALUE;

	/**战斗中的等级 */
	public lv: number = 1;

	/** 本次行动造成伤害的对象集合 */
	protected _curHurters: JXBattleEntity[] = [];

	protected _JxRole: JXRBRole = null;
	public get jxRole() {
		if (!this._JxRole) {
			this._JxRole = this.cmd.getRoleById(this.id)
		}
		return this._JxRole;
	}

	public addHurter(hurter: JXBattleEntity) {
		if (!this._curHurters) {
			this._curHurters = [];
		}
		for (let i = 0; i < this._curHurters.length; i++) {
			if (this._curHurters[i].id == hurter.id) {
				return;
			}
		}
		this._curHurters.push(hurter);
	}

	public popHurters() {
		let temp = this._curHurters;
		this._curHurters = [];
		return temp;
	}

	/** 上一次普通攻击的对象 */
	protected _lastComHurter: JXBattleEntity = null;
	public get lastComHurter() {
		return this._lastComHurter;
	}
	public set lastComHurter(hurter: JXBattleEntity) {
		this._lastComHurter = hurter;
		hurter.lastAtker = this;
	}

	/** 上一次普攻(或者立即伤害)自己的敌人(必要条件是自己可碰撞) */
	protected _lastAtker: JXBattleEntity = null;
	public get lastAtker() {
		return this._lastAtker;
	}
	public set lastAtker(atker: JXBattleEntity) {
		this._lastAtker = atker;
		// 只要是立即伤害，就会更新这个结构，所以在这里记录攻击方伤害的对象
		atker.addHurter(this);
	}

	constructor(type: JXBtlEntityType, roleType: JXBtlRT) {
		this.type = type;
		this.roleType = roleType;
		this.flag |= JXBtlPs.R.FLAG.PROPTS;
		this.buffs = [];
		this.buffMaps = new JXBattleMap<number, JXBattleBuff[]>();
		this.controlBuffs = [];
		this.proptEnvs = [];
	}

	public get isDie(): boolean {
		return !!(this.flag & JXBtlPs.R.FLAG.DIE);
	}


	/** 记录BUFF */
	public addBuff(buff: JXBattleBuff): JXBattleEntity {
		if (!this.buffs) {
			this.buffs = [];
		}
		this.buffs.push(buff);

		let buffs = this.buffMaps.get(buff.effect.nBufId);
		if (!buffs) {
			buffs = [];
			this.buffMaps.set(buff.effect.nBufId, buffs);
		}
		buffs.push(buff);
		return this;
	}

	/** 移除BUFF */
	public removeBuff(buff: JXBattleBuff) {
		if (!this.buffs) return;
		let buffs = this.buffMaps.get(buff.effect.nBufId);
		if (buffs) {
			JXBattleUtility.fastRemove(buffs, buff);
		}
		JXBattleUtility.remove(this.buffs, buff);
	}

	/** 添加控制的BUFF */
	public addControlBuff(buff: JXBattleBuff) {
		if (!this.controlBuffs) {
			this.controlBuffs = [];
		}
		this.controlBuffs.push(buff);
	}

	public removeControlBuff(buff: JXBattleBuff) {
		if (!this.controlBuffs) return;
		JXBattleUtility.remove(this.controlBuffs, buff);
	}



	/** 判断是否有某一类型的BUFF */
	public hasEffectById(nId: number): boolean {
		let buffs = this.buffMaps.get(nId);
		if (!buffs) return false;
		for (let i = 0; i < buffs.length; i++) {
			if (!buffs[i].isDestroy) return true;
		}
		return false;
	}

	/** 按照先后顺序获取某一类型的BUFF */
	public getEffectById(nId: number): JXBattleBuff[] {
		return this.buffMaps.get(nId) || [];
	}

	/** 获取该链上顶层的BUFF */
	public getTopEffectSameID(buff: JXBattleBuff): JXBattleBuff {
		let buffs = this.getEffectById(buff.effect.nBufId);
		if (!buffs) return buff;
		if (buffs.length == 0) return buff;
		for (let i = 0; i < buffs.length; i++) {
			if (!(buffs[i].isDestroy)) return buffs[i];
		}
	}

	/** 判断是否有某一种效果模型的BUFF */
	public hasEffectByBEM(nMold: JXBtlBEM): boolean {
		for (let i = 0; i < this.buffs.length; i++) {
			if (this.buffs[i].isCanActive && this.buffs[i].res.effectMold == nMold) {
				return true;
			}
		}
		return false;
	}

	/** 按照先后顺序获取某一些效果模型的BUFF */
	public getEffectByBEM(...nMolds: JXBtlBEM[]): JXBattleBuff[] {
		let buffs = [];
		for (let i = 0; i < this.buffs.length; i++) {
			if (this.buffs[i].isCanActive) {
				for (let j = 0; j < nMolds.length; j++) {
					if (nMolds[j] == this.buffs[i].res.effectMold) {
						buffs.push(this.buffs[i]);
						break;
					}
				}
			}
		}
		return buffs;
	}

	/** 是否有某一类效果类型的BUFF */
	public hasEffectByBEMT(nType: JXBtlBEMT): boolean {
		for (let i = 0; i < this.buffs.length; i++) {
			if (this.buffs[i].isCanActive && this.buffs[i].res.effectType == nType) {
				return true;
			}
		}
		return false;
	}

	/** 获取某一类效果类型BUFF  */
	public getEffectByBEMT(nType: JXBtlBEMT): JXBattleBuff[] {
		let buffs = [];
		for (let i = 0; i < this.buffs.length; i++) {
			if (this.buffs[i].isCanActive && this.buffs[i].res.effectType == nType) {
				buffs.push(this.buffs[i]);
			}
		}
		return buffs;
	}

	/**
	 * 根据指定模型，并且符合优先级条件，进行筛选，获取可生效的buff
	 * @param nType 要获取的效果模型
	 * @param pri 要判断的优先级
	 */
	public checkAndTakeBEM(nType: JXBtlBEM, priority: number): JXBattleBuff {
		let buffs = this.getEffectByBEM(nType);
		if (buffs.length == 0) return null;
		for (let i = 0; i < buffs.length; i++) {
			if (!buffs[i].isCanActive) continue;
			if (buffs[i].priority > priority) continue;
			buffs[i].take();
			return buffs[i];
		}
		return null;
	}

	/**
	 * 检测该BUFF是否被免疫（禁止添加到对象中）
	 * @param buff 被检测的BUFF
	 */
	public checkIsSpecialIm(buff: JXBattleBuff): JXBattleBuff {
		let buffs = this.getEffectByBEM(JXBtlBEM.ImByBuffId);
		for (let i = 0; i < buffs.length; i++) {
			if (!buffs[i].isCanActive) continue;
			if (buffs[i].propts != buff.effect.nBufId) continue;
			if (buffs[i].priority > buff.priority) continue;
			buffs[i].take();
			return buffs[i];
		}
		return null;
	}

	/**
	 * 根据优先级检测是否可以释放技能
	 * @param targetPri 目标优先级
	 * @param isEvent 是否记录事件
	 */
	public checkIsBanSkill(targetPri: number, isEvent: boolean): JXBattleBuff {
		if (targetPri <= JXBtlPs.S.PRI[JXBtlST.Global]) return null;
		let buffs = this.getEffectByBEM(JXBtlBEM.BanSkill, JXBtlBEM.BanAction);
		if (!buffs) return null;
		for (let i = 0; i < buffs.length; i++) {
			let buff = buffs[i];
			if (buff.isDestroy) continue;
			buff.take();
			isEvent && JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_CONTRLED, this.id, buff.res.effectMold, buff.uuid);
			return buff;
		}
		return null
	}

	/** 检测是否禁止普攻 */
	public checkIsBanComAtk() {
		let banBuff = this.checkAndTakeBEM(JXBtlBEM.BanAttack, JXBtlPs.S.PRI.Normal);
		if (banBuff) {
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_CONTRLED, this.id, JXBtlBEM.BanAttack, banBuff.uuid);
			return true;
		}
		banBuff = this.checkAndTakeBEM(JXBtlBEM.BanAction, JXBtlPs.S.PRI.Normal);
		if (banBuff) {
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_CONTRLED, this.id, JXBtlBEM.BanAction, banBuff.uuid);
			return true;
		}
		return false;
	}


	/** 检测是否还存在次数属性BUFF */
	public checkIsTimesPropts() {
		this.flag &= ~JXBtlPs.R.FLAG.TIMESPROPTS;
		for (let i = 0; i < this.buffs.length; i++) {
			let buff = this.buffs[i];
			if (buff.isDestroy) continue;
			if (!buff.isProptsBuff) continue;
			if (!buff.isTimesBuff) continue;
			this.flag |= JXBtlPs.R.FLAG.TIMESPROPTS;
			return;
		}
	}

	/** 获取加成后的属性 */
	public getPropts(nType: number): number {
		if (this.collision == JxBtlCollisionType.Null) {
			return 0;
		}
		if (!(this.flag & JXBtlPs.R.FLAG.PROPTS)) {
			return this.proptCaches[nType] || 0;
		}
		this.flag &= ~JXBtlPs.R.FLAG.PROPTS;
		this.proptCaches = JXBattleUtility.copyArray(this.propts);
		// 环境属性加成
		JXBattleUtility.addToPropts(this.proptEnvs, this.proptCaches);
		// BUFF属性加成
		for (let i = 0; i < this.buffs.length; i++) {
			let buff = this.buffs[i];
			if (buff.isDestroy) continue;
			if (!buff.isProptsBuff) continue;
			if (buff.isTimesBuff) continue;
			JXBattleUtility.addToPropts(buff.propts as number[], this.proptCaches);
		}

		for (let proptKey in JXBtlPs.MaxPts) {
			if (!JXBtlPs.MaxPts[proptKey]) return;
			let proptEnum = parseInt(proptKey);
			this.proptCaches[proptEnum] = JXBattleUtility.clamp(this.proptCaches[proptEnum], JXBtlPs.MaxPts[proptKey].min, JXBtlPs.MaxPts[proptKey].max);
		}

		// 将四种加成的的具体数值反应到实际属性中 加成数据属性在这里技术

		return this.proptCaches[nType] || 0;
	}

	public getBasePropts(nType: number) {
		return this.propts[nType] || 0;
	}

	/** 获取次数加成属性 */
	public getTimesPropts(nType: number, env?: number): number {
		let value: number = 0;
		for (let i = 0; i < this.buffs.length; i++) {
			let buff = this.buffs[i];
			if (!buff.isProptsBuff) continue;
			if (!buff.isTimesBuff) continue;
			if (!buff.propts[nType]) continue;
			if (buff.isDestroy) continue;
			value += buff.propts[nType];
			buff.take();
		}
		return value;
	}


	/** 进行锁血状态处理 */
	public onLockHp() {
		if (!(this.flag & JXBtlPs.R.FLAG.LOCKHP)) return;
		let lockBuff: JXBattleBuff;
		for (let i = 0; i < this.buffs.length; i++) {
			// 这里不需要判断是否属于可生效，因为这里锁血才是真正的状态标识
			// if (!this.buffs[i].isCanActive) continue;
			if (this.buffs[i].res.effectMold == JXBtlBEM.LockHp && (this.buffs[i].stateFlag & JXBtlPs.B.FLAG.LOCKHP_EFFECT)) {
				lockBuff = this.buffs[i];
				break;
			}
		}
		if (lockBuff) {
			this.onSkillAddHp(lockBuff);
			lockBuff.endLockHp();
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.CLEAR_LOCK_HP, this.id);
		this.flag &= ~JXBtlPs.R.FLAG.LOCKHP;
	}

	/** 控制的BUFF状态判定 */
	public onControlRoundBuff() {
		// 首先对控制的BUFF进行判定
		for (let i = 0; i < this.controlBuffs.length; i++) {
			let buff = this.controlBuffs[i];
			buff.onControlRoundBegin();
		}
		JXBtlMgr.ins.cleanWaitRemoveBuffs();
	}

	/** 身上的BUFF状态判定 isDie */
	public onStartRoundBuff(nRound: number) {
		let addHpBuffs = this.getEffectByBEMT(JXBtlBEMT.AddHp);
		for (let i = 0; i < addHpBuffs.length; i++) {
			addHpBuffs[i].active();
		}

		let damageBuffs = this.getEffectByBEMT(JXBtlBEMT.Damage);
		for (let i = 0; i < damageBuffs.length; i++) {
			damageBuffs[i].active();
		}

		let clearBuffs = this.getEffectByBEMT(JXBtlBEMT.Clear);
		for (let i = 0; i < clearBuffs.length; i++) {
			clearBuffs[i].active();
		}

		JXBtlMgr.ins.cleanWaitRemoveBuffs();
	}

	/** 技能判定 */
	public onNormalSkillAction(nRound: number): boolean {
		// 技能强制准备中，强制准备的技能只会有一个。
		let skill = MathEx.fisherYatesShuffle(this.skills)
		this.skills = skill;
		if (this.isSkillPrepare()) {
			for (let i = 0; i < this.skills.length; i++) {
				if (this.skills[i].state == JXBtlSSM.forcePreparing) {
					this.skills[i].onEnterSkill(nRound);
					break;
				}
			}
			return true;
		};

		for (let i = 0; i < this.skills.length; i++) {
			if (this.skills[i].isPursuit() || this.skills[i].isBeatback()) continue;
			// 准备回合，不是被动技能 -- 不通过
			if (nRound == JXBtlPs.FirstRd && !this.skills[i].isPassive()) continue;
			let banBuff = this.checkIsBanSkill(JXBtlPs.S.PRI[this.skills[i].skillRes.type], true);
			if (banBuff) continue;
			if (this.skills[i].onEnterSkill(nRound)) {
				// 不是被动技能，只能放一个技能
				if (!this.skills[i].isPassive()) return true;
			};
		}
		return false;
	}


	public calculatDamge(target: JXBattleEntity, type: number = JXBtlPs.C.WS): [number, boolean, boolean] {
		// 暴击系数计算
		let isCrit = JXBtlMgr.ins.random.getRandom() < this.getPropts(PART_PROPTS.BaoJi);
		//判断是否闪避
		let isEvade = JXBtlMgr.ins.random.getRandom() < target.getPropts(PART_PROPTS.ShanBi)
		let mulBaoji = isCrit ? this.getPropts(PART_PROPTS.BaoShang) : 1;
		switch (type) {
			case JXBtlPs.C.WS: {
				/**物理伤害&普攻伤害=（攻击-防御）*暴击系数*/
				let hurt = (this.getPropts(PART_PROPTS.GongJi) - target.getPropts(PART_PROPTS.FangYu)
					+ this.getPropts(PART_PROPTS.BingGong) - target.getPropts(PART_PROPTS.BingKang)
					+ this.getPropts(PART_PROPTS.HuoGong) - target.getPropts(PART_PROPTS.HuoKang)) * mulBaoji;
				return [hurt, isCrit, isEvade]
			}
			case JXBtlPs.C.CT: {
				/**穿透伤害无视防御=（攻击）*暴击系数 */
				let hurt = (this.getPropts(PART_PROPTS.GongJi) + this.getPropts(PART_PROPTS.BingGong) + this.getPropts(PART_PROPTS.HuoGong)) * mulBaoji;
				return [hurt, isCrit, isEvade]
			}
			case JXBtlPs.C.BZ: {
				/**无视对方闪避效果 */
				let hurt = (this.getPropts(PART_PROPTS.GongJi) - target.getPropts(PART_PROPTS.FangYu)
					+ this.getPropts(PART_PROPTS.BingGong) - target.getPropts(PART_PROPTS.BingKang)
					+ this.getPropts(PART_PROPTS.HuoGong) - target.getPropts(PART_PROPTS.HuoKang)) * mulBaoji;
				return [hurt, isCrit, false]
			}
			case JXBtlPs.C.WS2: {
				let ws = this.getPropts(PART_PROPTS.GongJi) - target.getPropts(PART_PROPTS.FangYu);
				let bs = this.getPropts(PART_PROPTS.BingGong) - target.getPropts(PART_PROPTS.BingKang);
				let hs = this.getPropts(PART_PROPTS.HuoGong) - target.getPropts(PART_PROPTS.HuoKang);
				let hurt = 0;
				hurt = Math.max(ws, bs, hs);
				return [hurt, isCrit, isEvade]
			}
		}
	}

	/**计算额外伤害 */
	public calculateDamageMul(fDamage: number, atker: JXBattleEntity, hurter: JXBattleEntity, env?: number): number {
		let atkerRace = atker.raceType;
		let hurterRace = hurter.raceType;
		let mulRace = 0;
		fDamage = fDamage * (1 + mulRace);
		if (fDamage <= 0) { fDamage = 0 }
		return fDamage;
	}



	/**
	 * 受伤扣血
	 * @param fDamage 伤害数值
	 * @param isHurtToHurt 是否来自反伤
	 */
	public onHurt(fDamage: number, isHurtToHurt: boolean = false): [number, number, JXBattleBuff] {
		let oldTemp = this._tempHp;
		fDamage = Math.floor(fDamage);
		if (this.jxRole) {
			this.jxRole.changePreState()
		}
		// 扣盾: 存在护盾的话，优先扣盾
		if (this._tempHp > 0) {
			this.tempHp = JXBattleUtility.clamp(this._tempHp - fDamage, 0, this._tempHp);
			let changeNum = oldTemp - this._tempHp;
			if (changeNum >= fDamage) {
				return [0, changeNum, null];
			}
			fDamage = fDamage - changeNum;
		}
		// 扣血
		let oldHp = this.curHp;
		this.curHp = JXBattleUtility.clamp(this.curHp - Math.floor(fDamage), 0, this.maxHp);
		if (this.curHp <= 0) {
			if (this.flag & JXBtlPs.R.FLAG.LOCKHP) {
				this.curHp = 1;
				JXBtlMgr.ins.onEvent(JXBattleEvt.LOCK_HP_EFFECT, this.id, Math.floor(fDamage));
				return [0, 0, null];
			}
			else {
				let lockBuffs = this.getEffectByBEM(JXBtlBEM.LockHp);
				if (lockBuffs.length > 0) {
					lockBuffs[JXBtlArrIx.Zero].startLockHp();
					lockBuffs[JXBtlArrIx.Zero].take();

					this.curHp = 1;
					this.flag |= JXBtlPs.R.FLAG.LOCKHP;
					JXBtlMgr.ins.onEvent(JXBattleEvt.LOCK_HP_EFFECT, this.id, Math.floor(fDamage));
				}
				else {
					this.onDie();
				}
			}

		}
		return [Math.floor(oldHp - this.curHp), oldTemp, null]
	}

	/** 技能伤害 , 实际造成的伤害数值*/
	public onSkillHurt(buff: JXBattleBuff): JXAnsHurtInfo {
		let fDamage = buff.propts as number;
		let fProtect = 0;
		let execer = buff.effect.skill.our;
		let imBuff: JXBattleBuff = null;
		fDamage = this.calculateDamageMul(fDamage, execer, this, buff.effect.nBufId);
		[fDamage, fProtect, imBuff] = this.onHurt(fDamage);
		let hurtInfo: JXAnsHurtInfo = {
			insId: null,
			execer: execer.id,
			target: this.id,
			damage: fDamage,
			protect: fProtect,
			isCrit: !!(buff.stateFlag & JXBtlPs.B.FLAG.CRIT),
			insBuff: buff.ansBuff.insId,
			isImDamage: imBuff != null,
			targetIsDie: this.isDie
		};
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_SKILL_HURT, this.id, hurtInfo);
		buff.ansBuff.effects.push(hurtInfo.insId);
		if (imBuff && imBuff.isDestroy) {
			imBuff.setDestroy();
		}
		if (this.isDie) {
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_DIE, this.id);
		}
		return hurtInfo;
	}

	/** 技能回血 */
	public onSkillAddHp(buff: JXBattleBuff): JXAnsAddHpInfo {
		let fAddHp = buff.propts as number;
		let isProtect = JXBtlPs.B.PROTECTS.indexOf(buff.res.effectMold) != JXBtlPs.Invalid;
		if (!isProtect) {
			fAddHp = this.onAddHp(fAddHp);
			if (fAddHp <= 0) fAddHp = 0;
		} else {
			fAddHp = this.onAddHp(fAddHp, isProtect);
		}
		if (!fAddHp) return null;
		let ansAddHp: JXAnsAddHpInfo = {
			insId: null,
			execer: buff.effect.skill.our.id,
			target: this.id,
			isProtect: isProtect,
			isCrit: !!(buff.stateFlag & JXBtlPs.B.FLAG.CRIT),
			addNum: fAddHp,
			insBuff: buff.uuid
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_SKILL_ADDHP, this.id, ansAddHp);
		buff.ansBuff.effects.push(ansAddHp.insId);
		return ansAddHp;
	}


	/** 技能添加最大生命值 */
	public onSkillAddMaxHp(buff: JXBattleBuff): JXAnsAddMaxHpInfo {
		let fAddMax: number = Math.floor(buff.propts[JXBtlPs.R.PORPTS.MAXHP] || 0);
		if (fAddMax <= 0) return;
		let oldMax = this.maxHp;
		let oldCur = this.curHp;
		this.maxHp = oldMax + fAddMax;
		this.curHp = oldCur + fAddMax;
		let ansAddMaxHp: JXAnsAddMaxHpInfo = {
			insId: null,
			execer: buff.effect.skill.our.id,
			target: this.id,
			insBuff: buff.uuid,
			addNum: Math.floor(fAddMax),
			oldMaxHp: oldMax
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_SKILL_ADDMAXHP, this.id, ansAddMaxHp);
		buff.ansBuff.effects.push(ansAddMaxHp.insId);
		return ansAddMaxHp;
	}


	/** 输出检测 */
	public onAtkingEvent(hurter: JXBattleEntity, ansHurtInfo: JXAnsHurtInfo, fromBuff?: JXBattleBuff) {
		this.onAtk2Hp(ansHurtInfo);
		this.onAtk2Protect(ansHurtInfo);
	}

	/** 受伤检测 */
	public onHurtingEvent(atker: JXBattleEntity, ansHurtInfo: JXAnsHurtInfo, fromBuff?: JXBattleBuff) {
		if (this.isDie) return;
		if (ansHurtInfo.isImDamage) return;
		if (fromBuff && !fromBuff.lifeTimer) {
			this.lastAtker = atker;
		}
		this.onHurt2Atk(atker, ansHurtInfo, fromBuff);
		this.onHurt2Hp(atker, ansHurtInfo);
		this.onHurt2Protect(atker, ansHurtInfo);
	}

	/** 受击回血 */
	protected onHurt2Hp(atker: JXBattleEntity, ansFrom: JXAnsHurtInfo,): boolean {
		if (this.isDie) return;
		let buffs = this.getEffectByBEM(JXBtlBEM.HurtToHp);
		if (buffs.length == 0) return;
		let buff = buffs[JXBtlArrIx.Zero];
		let isBanAddHp = this.checkAndTakeBEM(JXBtlBEM.BanAddHp, buff.priority);
		if (isBanAddHp) return;
		let execer = buff.effect.skill.our;
		let value = execer.getPropts(buff.propts[JXBtlArrIx.Zero]) * buff.propts[JXBtlArrIx.One];
		let rate = buff.runtimeRate;
		if (value == 0) return;
		let isEffect = JXBtlMgr.ins.random.getRandom() < rate;
		if (!isEffect) return;

		value = this.onAddHp(value);
		let ansHu2HpInfo: JXAnsAddHpInfo = {
			insId: null,
			execer: execer.id,
			target: this.id,
			addNum: value,
			insHurt: ansFrom.insId,
			insBuff: buffs[0].uuid
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_HURT_2_HP, this.id, ansHu2HpInfo);
		ansFrom.ins2DefHp = ansHu2HpInfo.insId;
		return true;
	}

	/** 受击回盾 */
	protected onHurt2Protect(atker: JXBattleEntity, ansFrom: JXAnsHurtInfo): boolean {
		if (this.isDie) return;
		let buffs = this.getEffectByBEM(JXBtlBEM.HurtToProtect);
		if (buffs.length == 0) return;
		let buff = buffs[JXBtlArrIx.Zero];
		let isBanAddProtect = this.checkAndTakeBEM(JXBtlBEM.BanProtect, buff.priority);
		if (isBanAddProtect) return;
		let execer = buff.effect.skill.our;
		let addNum = execer.getPropts(buff.propts[JXBtlArrIx.Zero]) * buff.propts[JXBtlArrIx.One];
		let rate = buff.runtimeRate;
		let isEffect = JXBtlMgr.ins.random.getRandom() < rate;
		if (!isEffect) return;

		addNum = this.onAddHp(addNum, true);
		let ansH2PInfo: JXAnsAddHpInfo = {
			insId: null,
			execer: execer.id,
			target: this.id,
			addNum: addNum,
			insHurt: ansFrom.insId,
			insBuff: buffs[0].uuid,
			isProtect: true
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_HURT_2_PROTECT, this.id, ansH2PInfo);
		ansFrom.ins2DefHp = ansH2PInfo.insId;
		return true;
	}


	/** 回血 */
	public onAddHp(fAddHp: number, isTemp: boolean = false): number {
		fAddHp = Math.floor(fAddHp)
		if (isTemp) {
			let oldTemp = this.tempHp;
			let nNewTemp = this.tempHp + fAddHp;
			this.tempHp = JXBattleUtility.clamp(nNewTemp, 0, this.maxHp * JXBtlPs.MaxPts.ProtectWithMaxHp);
			return this.tempHp - oldTemp;
		}
		let oldHp = this.curHp;
		let nNewHp = this.curHp + fAddHp;
		this.curHp = JXBattleUtility.clamp(nNewHp, 0, this.maxHp);
		return this.curHp - oldHp;
	}


	/** 反弹伤害404 */
	protected onHurt2Atk(atker: JXBattleEntity, ansFrom: JXAnsHurtInfo, fromBuff?: JXBattleBuff): boolean {
		let fDamage = ansFrom.damage;
		if (fDamage == 0) return;
		if (atker.isDie || atker.collision != JxBtlCollisionType.Normal) return;
		let buffs = this.getEffectByBEM(JXBtlBEM.HurtToAtk);
		let fSkillMul = 0, rate = 0;
		for (let i = 0; i < buffs.length; i++) {
			if (!buffs[i].isCanActive) continue;
			fSkillMul += buffs[i].propts as number;
			rate = Math.max(rate, buffs[i].runtimeRate || 0);
		}
		if (fSkillMul <= 0) return;
		let isEffect = JXBtlMgr.ins.random.getRandom() < rate;
		if (!isEffect) return;
		fDamage = fDamage * fSkillMul;
		let imBuff: JXBattleBuff, fProtect;
		[fDamage, fProtect, imBuff] = atker.onHurt(fDamage);

		let ansD2DInfo: JXAnsHurtInfo = {
			insId: null,
			execer: this.id,
			target: atker.id,
			damage: fDamage,
			protect: fProtect,
			insFromHurt: ansFrom.insId,
			isImDamage: imBuff != null,
			targetIsDie: atker.isDie,
			insBuff: buffs[0].uuid
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_HURT_2_ATK, atker.id, ansD2DInfo);
		ansFrom.ins2Hurt = ansD2DInfo.insId;
		if (imBuff && imBuff.isDestroy) {
			imBuff.setDestroy();
		}
		if (atker.isDie) {
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_DIE, atker.id);
		}
	}


	/** 输出吸血403 */
	protected onAtk2Hp(ansHurtInfo: JXAnsHurtInfo) {
		let fDamage = ansHurtInfo.damage + ansHurtInfo.protect;
		if (fDamage == 0) return;
		let banBuff = this.checkAndTakeBEM(JXBtlBEM.BanAddHp, JXBtlPs.S.PRI.Normal);
		if (banBuff) return;
		let buffs = this.getEffectByBEM(JXBtlBEM.AtkToHp);
		let fSkillMul = 0;
		let rate = 0;
		for (let i = 0; i < buffs.length; i++) {
			if (!buffs[i].isCanActive) continue;
			fSkillMul += buffs[i].propts as number;
			rate = Math.max(rate, buffs[i].runtimeRate || 0);
		}
		if (fSkillMul == 0) return;
		let isEffect = JXBtlMgr.ins.random.getRandom() < rate;
		if (!isEffect) return;
		let nAddHp = (fDamage * fSkillMul);
		nAddHp = this.onAddHp(nAddHp);
		if (nAddHp <= 0) nAddHp = 0;
		let ansD2HInfo: JXAnsAddHpInfo = {
			insId: null,
			target: this.id,
			execer: this.id,
			insHurt: ansHurtInfo.insId,
			addNum: nAddHp,
			insBuff: buffs[0].uuid,
		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_ATK_2_HP, this.id, ansD2HInfo);
		ansHurtInfo.ins2AtkHp = ansD2HInfo.insId;
	}

	/** 输出伤害转护盾 */
	protected onAtk2Protect(ansHurtInfo: JXAnsHurtInfo) {
		let fDamage = ansHurtInfo.damage + ansHurtInfo.protect;
		if (fDamage == 0) return;
		let banBuff = this.checkAndTakeBEM(JXBtlBEM.BanProtect, JXBtlPs.S.PRI.Normal);
		if (banBuff) return;
		let buffs = this.getEffectByBEM(JXBtlBEM.AtkToProtect);
		let fSkillMul = 0;
		let rate = 0;
		for (let i = 0; i < buffs.length; i++) {
			if (!buffs[i].isCanActive) continue;
			fSkillMul += buffs[i].propts as number;
			rate = Math.max(rate, buffs[i].runtimeRate || 0);
		}
		if (fSkillMul == 0) return;
		let isEffect = JXBtlMgr.ins.random.getRandom() < rate;
		if (!isEffect) return;
		// 暂时不被任何加成所影响
		let addNum = fDamage * fSkillMul;
		addNum = this.onAddHp(addNum, true);
		let ansA2PInfo: JXAnsAddHpInfo = {
			insId: null,
			target: this.id,
			execer: this.id,
			insHurt: ansHurtInfo.insId,
			addNum: addNum,
			isProtect: true,
			insBuff: buffs[0].uuid,

		}
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_ATK_2_PROTECT, this.id, ansA2PInfo);
		ansHurtInfo.ins2AtkHp = ansA2PInfo.insId;
	}



	/** 死亡了~~ */
	public onDie() {
		this.flag |= JXBtlPs.R.FLAG.DIE;
		// 清除状态，清除BUFF
		for (let i = 0; i < this.buffs.length; i++) {
			this.buffs[i].setDestroy();
		}
		for (let i = 0; i < this.controlBuffs.length; i++) {
			let buff = this.controlBuffs[i];
			if (!buff.effect.skill.isGlobal()) {
				buff.setDestroy();
			}
		}
		JXBtlMgr.ins.cleanWaitRemoveBuffs();
	}

	/**
 * 清除目标效果模型的BUFF
 * @param execBuff 执行该操作的BUFF
 * @param targetType 目标效果模型
 */
	public clearBuffsByEffectType(execBuff: JXBattleBuff, targetType: JXBtlBEMT) {
		let buffs = this.getEffectByBEMT(targetType);
		let nClCount = (execBuff.propts as number) || buffs.length;
		for (let i = buffs.length - 1; i >= 0; i--) {
			if (nClCount == 0) break;
			// 全局技能不可被清理
			if (buffs[i].isDestroy) continue;
			// 优先级较高的效果不能被清除
			if (buffs[i].priority < execBuff.priority) continue;
			buffs[i].setDestroy();
			execBuff.take();
			nClCount--;
		}
	}


	/**
	 * 清除某一个ID的BUFF
	 * @param execBuff 执行该操作的BUFF
	 */
	public clearBuffsByEffectId(execBuff: JXBattleBuff) {
		let targetBuffs = this.getEffectById(execBuff.propts as number);
		for (let i = 0; i < targetBuffs.length; i++) {
			if (targetBuffs[i].isDestroy) continue;
			if (targetBuffs[i].priority < execBuff.priority) continue;
			targetBuffs[i].setDestroy();
			execBuff.take();
		}
	}

	public isSkillPrepare(): boolean {
		for (let i = 0; i < this.skills.length; i++) {
			if (this.skills[i].state == JXBtlSSM.forcePreparing) {
				return true;
			}
		}
	}

	/**
	   * 角色回合结束
	   */
	public onEndRound() {
		for (let i = 0; i < this.buffs.length; i++) {
			if (this.buffs[i].isDestroy) continue;
			this.buffs[i].resetRoundEffect();
		}
	}



}

/** 队伍实体： 表示队伍中的参战对象 */
export class JXBattleTeamEntiry extends JXBattleEntity {
	/** 所属的队伍 */
	public team: JXBattleTeam;

	bindTeam(team: JXBattleTeam) {
		this.team = team;
		this.camp = team.camp;
		return this;
	}

	update(dt) {
		this.cTime += dt;
		if (this.cTime >= this.cd) {
			this.cTime = 0;
			//确定是角色是否结束
			if (this.jxRole.checkRoleIsEnd()) {
				this.roleStartAction();
				this.curRound++;
			}
		}
	}

	protected roleStartAction() {
		let buffStep = new JXBattleBuffTake(this, this.curRound);
		JXBtlMgr.ins.addStep(buffStep);
		JXBtlMgr.ins.workSteps();
		this.onEndRound();
		this.curInitiSkillId = INVALID_VALUE;
	}


	/** 普攻判定:本回合攻击次数, 指定的攻击目标
	   *  返回是否完成普攻
	   */
	public onComAttack(nTimes: number, target?: JXBattleTeamEntiry): JXAnsHurtInfo {
		/** 是否禁止普攻 */
		let isBanAtk = this.checkIsBanComAtk();
		if (isBanAtk) return null;
		/**没有符合条件的攻击目标 */
		if (!target) {
			let candidates = [];
			let role = this.jxRole;
			let pos: cc.Vec2 = null;
			pos = this.cmd.btlMapConverts.converToMapPos(role.birthPos);
			candidates.push(...this.team.enemyTeam().getRolesByPos(pos, this.scopeId))
			if (candidates.length > 0) {
				candidates = MathEx.fisherYatesShuffle(candidates);
				let index = MathEx.random(0, candidates.length - 1);
				target = candidates[index];
			}
		}
		if (!target) { return null }
		if (this.camp === target.camp || this.id === target.id) {
			return null
		}
		let [fHurt, isCrit, isEvade] = this.calculatDamge(target);
		/**最终伤害加成 */
		let fProtect: number;
		fHurt = this.calculateDamageMul(fHurt, this, target);
		[fHurt, fProtect] = target.onHurt(fHurt);
		let ansHurtInfo: JXAnsHurtInfo = {
			insId: null,
			execer: this.id,
			target: target.id,
			protect: fProtect,
			damage: fHurt,
			isCrit: isCrit,
			targetIsDie: target.isDie,
			isImDamage: isEvade
		}
		this.lastComHurter = target
		// 输出事件
		this.onAtkingEvent(target, ansHurtInfo);
		// 受击事件
		target.onHurtingEvent(this, ansHurtInfo);
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_COM_ATK, target.id, ansHurtInfo);
		if (target.isDie) {
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_DIE, target.id);
		}
		return ansHurtInfo;
	}



	/** 普攻之后，获取追击技能 */
	public onAfterComAttack(nRound: number): JXBattleSkill {
		// 追击检测
		let skills = this.skills;
		for (let i = 0; i < skills.length; i++) {
			if (!skills[i].isPursuit()) continue;
			// 被禁了
			if (skills[i].onEnterSkill(nRound)) {
				// 触发追击技能,将追击动作插入队列
				return skills[i];
			};
		}
		return null;
	}

	/** 反击检测 */
	public onBeatbackSkill(nRound: number) {
		for (let i = 0; i < this.skills.length; i++) {
			if (!this.skills[i].isBeatback()) continue;
			if (this.skills[i].onEnterSkill(nRound)) {
				return this.skills[i];
			};
		}
		return null;
	}


	/** 连击检测 */
	public onCombo() {
		let buffs = this.getEffectByBEM(JXBtlBEM.DBHit);
		for (let i = 0; i < buffs.length; i++) {
			if (buffs[i].isRoundEffect) continue;
			buffs[i].take(true);
			return true;
		}
		return false;
	}



}

export class JXBattleHero extends JXBattleTeamEntiry {
	public res: SHeroDataRaw;
	constructor(card: IHeroBtlData, team: JXBattleTeam, index: number) {
		super(JXBtlEntityType.Role, JXBtlRT.Card);
		this.id = card.heroId;
		this.posiiton = index;
		this.cmd = team.cmd;
		this.collision = JxBtlCollisionType.Normal;
		this.bindTeam(team)
		this.res = JXBattleCb.getCardData(card.tableId);
		this.roleType = this.res.type;
		this.scopeId = this.res.scope;
		this.cd = this.res.cd;
		this.propts = JXMath.newArray(EnumUtil.size(PART_PROPTS));
		for (let i: number = 0; i < card.propts.length; i++) {
			this.propts[i] = card.propts[i];
		}
		this.propts[JXBtlPs.R.PORPTS.MAXHP] = this.maxHp = Math.floor(card.maxHp);
		this.curHp = Math.floor(card.curHp == null ? this.maxHp : card.curHp);
		this.tempHp = 0;
		if (!this.propts[PART_PROPTS.FormulaMaxHp]) {
			this.propts[PART_PROPTS.FormulaMaxHp] = this.maxHp;
		}
		this.lv = 1;
		this.heroType = this.res.type;
		JXBtlMgr.ins.anlysis.setMaxHp(this.id, this.maxHp, this.curHp);
		this.skills = [];
		/**打乱数组 */
		let skillIds = card.skillIds;
		for (let i = 0; i < skillIds.length; i++) {
			this.skills[i] = new JXBattleSkill(skillIds[i], i);
			this.skills[i].our = this;
		}
	}
}

/** 队伍环境对象 */
export class JXBattleTeamAmbienter extends JXBattleTeamEntiry {
	constructor(skills: number[][], index: number, team: JXBattleTeam, from?: string) {
		super(JXBtlEntityType.Ambient, JXBtlRT.Ambient);
		this.id = from ? from : JXBattleUtility.AmbientGtor.getNewId();
		this.collision = JxBtlCollisionType.Null;
		this.posiiton = index;
		this.bindTeam(team);

		this.skills = [];
		for (let i = 0; i < skills.length; i++) {
			this.skills[i] = new JXBattleSkill(skills[i][JXBtlArrIx.Zero], i);
			this.skills[i].our = this;
		}

		JXBtlMgr.ins.anlysis.setExtra({
			id: this.id,
			position: this.posiiton,
			collisiton: this.collision,
			type: this.type,
			camp: this.team.camp,
			skills
		})
	}

}


/** 全局环境对象 */
export class JXBattleAmbienter extends JXBattleEntity {
	/**
	 * 
	 * @param skills 技能组
	 * @param index 位置索引，用来确认来源
	 * @param from 来源，辅助确认来源用来标识ID
	 */
	constructor(skills: number[][], index: number, from?: string) {
		super(JXBtlEntityType.Ambient, JXBtlRT.Ambient);
		this.collision = JxBtlCollisionType.Null;
		this.posiiton = index;
		this.id = from ? from : JXBattleUtility.AmbientGtor.getNewId();
		this.skills = [];
		for (let i = 0; i < skills.length; i++) {
			this.skills[i] = new JXBattleSkill(skills[i][JXBtlArrIx.Zero], i);
			this.skills[i].our = this;
		}

		JXBtlMgr.ins.anlysis.setExtra({
			id: this.id,
			position: this.posiiton,
			collisiton: this.collision,
			type: this.type,
			skills,
			camp: this.camp,
		})
	}
}